using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using Pretorianie.Tytan.Core.Interfaces;

namespace Pretorianie.Tytan.Core.CustomAddIn
{
    /// <summary>
    /// Class that manages the collection of IPackageActions.
    /// </summary>
    public class CustomAddInActionDictionary
    {
        private readonly IList<IPackageAction> data = new List<IPackageAction>();

        /// <summary>
        /// Adds specified instance of refactoring option or overwrites the existing one with the same name.
        /// </summary>
        public void Add(IPackageAction action)
        {
            if (action != null && !data.Contains(action))
                data.Add(action);
        }


        #region Properties

        /// <summary>
        /// Gets the number of stored refactoring options.
        /// </summary>
        public int Count
        {
            get { return data.Count; }
        }

        /// <summary>
        /// Gets the list of available refactor options.
        /// </summary>
        public ICollection<IPackageAction> Actions
        {
            get { return data; }
        }

        #endregion

        #region Discovery

        /// <summary>
        /// Gets all available refactoring options generated by automatically scanning of currently executed assembly.
        /// </summary>
        public static CustomAddInActionDictionary AutoDiscoverRefactorOptions(params Assembly[] assemblies)
        {
            try
            {
                CustomAddInActionDictionary dict = new CustomAddInActionDictionary();
                Type generalType = typeof(IPackageAction);

                foreach (Assembly a in assemblies)
                {
                    Type[] availableTypes = a.GetTypes();

                    foreach (Type type in availableTypes)
                    {
                        if (!type.IsAbstract && generalType.IsAssignableFrom(type))
                        {
                            try
                            {
                                // store for future usage:
                                dict.Add(Activator.CreateInstance(type) as IPackageAction);
                            }
                            catch (TargetInvocationException e)
                            {
                                Trace.TraceError(e.ToString());
                            }
                            catch (ArgumentException e)
                            {
                                Trace.TraceError(e.ToString());
                            }
                            catch (MissingMethodException e)
                            {
                                Trace.TraceError(e.ToString());
                            }
                        }
                    }
                }

                return dict;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
                throw;
            }
        }

        #endregion


        /// <summary>
        /// Performs the cleanup actions.
        /// </summary>
        public void Dispose()
        {
            // notify about the exit event:
            foreach (IPackageAction addIn in data)
                addIn.Dispose();

            data.Clear();
        }
    }
}